﻿package Core 
{
	import com.junkbyte.console.Cc;
	import Common.Utils;
		
	import com.greensock.TweenMax;
	
	import Common.Constants;	
	import Common.ImageInfo;
	import Common.Preloader;
	import Common.NormalCheckbox;
	import Events.ImageEvent;
	import Network.XMLLoader;	
	
	import fl.motion.AdjustColor;	
	import flash.filters.BlurFilter;
	import flash.filters.ColorMatrixFilter;
	import flash.filters.DropShadowFilter;
	import flash.events.DataEvent;
	import flash.events.IOErrorEvent;
	import flash.events.SecurityErrorEvent;
	import flash.geom.ColorTransform;
	import flash.geom.Rectangle;
	import flash.geom.Matrix;	
	import flash.geom.Point;		
	import flash.display.Bitmap;
	import flash.display.Loader;
	import flash.display.Sprite;
	import flash.display.BitmapData;
	import flash.events.Event;	
	import flash.events.MouseEvent;
	import flash.net.URLLoader;	
	import flash.net.URLRequest;	
	/**
	 * ...
	 * @author Serg de Adelantado
	 */
	[Event(name = 'IMAGE_LOADED', type = "Events.ImageEvent")]
	[Event(name = 'IMAGE_UPLOADED', type = "Events.ImageEvent")]
	[Event(name = 'IMAGE_UPDATED', type = "Events.ImageEvent")]
	[Event(name = 'UPDATE_COMPLETE', type = "Events.ImageEvent")]
	[Event(name = 'UPDATE_ERROR', type = "Events.ImageEvent")]
	[Event(name = 'DELETER_OVER', type = "Events.ImageEvent")]
	[Event(name = 'DELETER_OUT', type = "Events.ImageEvent")]
	[Event(name = 'progress', type = "Events.ImageProgressEvent")]
	public class ImageContainer extends Sprite
	{
		protected var FViewer:ImagesViewer;
		protected var FBitmap:Bitmap;		
		protected var FSize:Point;		
		protected var FIsLocal:Boolean;		
		protected var FIsLoaded:Boolean;
		protected var FPreloader:Preloader;
		protected var FDescriptor:ImageDescriptor;
		protected var FTools:ImageTools;
		protected var FToolsMask:Sprite;
		protected var FColor:AdjustColor;
		protected var FFilter:ColorMatrixFilter;
		protected var FDeleter:ImageDeleter;
		protected var FRotation:int;		
		protected var FRotationToSend:int;
		protected var FRoomsStorage:XMLLoader;
		protected var FUpdater:URLLoader;
		protected var FCheckUpdates:Boolean;
		protected var FNeedUpdate:Boolean;
		protected var FOldOwner:int;
		protected var FSelector:NormalCheckbox;
		protected var FSelectionSpike:Sprite;
		protected var FSelected:Boolean;
		//MySQL saving params
		protected var FID:int;
		protected var FDelete:uint;
		protected var FOldType:int;
		protected var FObjectID:int;
		protected var FOwnerType:int;
		protected var FOrder:int;
		protected var FStartDescription:String;
		protected var FShadowFilter:Object;
		
		public function ImageContainer(AWidth:int, AHeight:int)
		{
			FOwnerType = 1;
			FOrder = -1;
			FID = -1;
			FOldType = -1;
			useHandCursor = true;
			buttonMode = true;
			doubleClickEnabled = true;
			cacheAsBitmap = true;
			FIsLocal = false;
			FSize = new Point(AWidth, AHeight);
			FRotation = FRotationToSend = 0;
			alpha = 1;
			focusRect = false;
			FCheckUpdates = false;
			FNeedUpdate = false;
			FSelected = false;
			FStartDescription = '';
			
			graphics.beginFill(Constants.IMAGE_BACKGROUND);
			graphics.drawRect(0, 0, FSize.x, FSize.y);
			graphics.endFill();
			
			FDescriptor = new ImageDescriptor(this, AWidth, AHeight);
			FDescriptor.y = AHeight;
			addChild(FDescriptor);
			
			FDeleter = new ImageDeleter(this);
			FDeleter.addEventListener(MouseEvent.MOUSE_OVER, OnDeleterOver);
			FDeleter.addEventListener(MouseEvent.MOUSE_OUT, OnDeleterOut);
			
			FColor = new AdjustColor();
			FColor.saturation = -100;
			FColor.brightness = -25;
			FColor.contrast = 0;
			FColor.hue = 0;		
			FFilter = new ColorMatrixFilter(FColor.CalculateFinalFlatArray());
			FShadowFilter = new Object();
			FShadowFilter.color = 0;
			FShadowFilter.alpha = 1;
			FShadowFilter.blurX = 5;
			FShadowFilter.blurY = 5;
			FShadowFilter.distance = 0;
			FShadowFilter.quality = 3;
			FShadowFilter.strength = 1;
			TweenMax.to(this, 0, { dropShadowFilter:FShadowFilter } );
			
			FTools = new ImageTools();
			FTools.Image = this;
			FTools.Width = AWidth;
			FTools.y = AHeight - FTools.Height;			
			addChild(FTools);
			
			FToolsMask = new Sprite();
			FToolsMask.graphics.beginFill(0);
			FToolsMask.graphics.drawRect(0, 0, FSize.x, FSize.y);
			FToolsMask.graphics.endFill();
			addChild(FToolsMask);
			FTools.mask = FToolsMask;
			
			FSelector = new NormalCheckbox();
			FSelector.addEventListener(MouseEvent.MOUSE_DOWN, OnSelector);
			addChild(FSelector);
			FSelector.x = 1;
			FSelector.y = 1;			
			
			addEventListener(MouseEvent.MOUSE_OVER, OnMouseOver);
			addEventListener(MouseEvent.MOUSE_OUT, OnMouseOut);
			addEventListener(Event.ADDED_TO_STAGE, OnAddedToStage);
		}
		
		private function OnDeleterOver(e:MouseEvent):void 
		{
			dispatchEvent(new ImageEvent(ImageEvent.DELETER_OVER));
		}
		
		private function OnDeleterOut(e:MouseEvent):void 
		{
			dispatchEvent(new ImageEvent(ImageEvent.DELETER_OUT));
		}
		
		private function OnSelector(e:MouseEvent):void 
		{
			Selected = !Selected;
			if (FSelected)			
				FViewer.AddToSelection(this);
			else
				FViewer.DropSelection(this);
		}
		
		private function OnAddedToStage(e:Event):void 
		{
			removeEventListener(Event.ADDED_TO_STAGE, OnAddedToStage);
			FViewer = ImagesViewer(parent.parent);
		}
		
		private function AddIcon(AName:Class):Bitmap
		{
			var vResult:Bitmap;
			vResult = new Bitmap(new AName());			
			vResult.visible = false;
			addChild(vResult);
			return vResult;
		}
		
		public function Mark(AColor:uint):void 
		{
			graphics.clear();
			graphics.beginFill(AColor);
			graphics.drawRect(0, 0, FSize.x, FSize.y);			
			graphics.endFill();			
		}
		
		public function get Selected():Boolean
		{ 
			return FSelected;
		}
		
		public function set Selected(ASelected:Boolean):void
		{		
			FSelected = ASelected;
			FSelector.Selected = FSelected;
			if (FSelected)			
				Mark(Constants.IMAGE_SELECTED);			
			else			
				Mark(Constants.IMAGE_BACKGROUND);
		}
		
		public function NotifyUpdate():void
		{
			if(FCheckUpdates)
				FNeedUpdate = true;			
		}
		
		protected function OnMouseOver(e:MouseEvent):void 
		{
			FShadowFilter.alpha = 0;
			TweenMax.to(this, 0.5, {dropShadowFilter:FShadowFilter});
		}
		
		protected function OnMouseOut(e:MouseEvent):void 
		{
			FShadowFilter.alpha = 1;
			TweenMax.to(this, 0.5, {dropShadowFilter:FShadowFilter});
		}	
		
		public function Load():void
		{}
			
		protected function ProcessBitmap(ABitmap:Bitmap):void 
		{			
			var vBitmap:Bitmap = ABitmap;
			vBitmap.smoothing = true;
			var vOriginal:Point = new Point(vBitmap.width, vBitmap.height);						
			ImageUtils.Resize(vBitmap, FSize.x - 5, FSize.y - 5);			
			var vMatrix:Matrix = new Matrix();
			vMatrix.scale(vBitmap.width / vOriginal.x, vBitmap.height / vOriginal.y);
			var vResult:BitmapData = new BitmapData(vBitmap.width, vBitmap.height, false);
			vResult.draw(vBitmap, vMatrix);
			FBitmap = new Bitmap(vResult);
			vBitmap.bitmapData.dispose();
			vBitmap = null;
			vMatrix = null;
			FBitmap.x = (FSize.x - FBitmap.width) / 2;
			FBitmap.y = (FSize.y - FBitmap.height) / 2;
			addChild(FBitmap);			
			addChild(FDeleter);
			addChild(FTools);
			addChild(FSelector);
		}
		
		public function StartUpload():void
		{
			if (NeedUpdate) 
				trace('Image with ID ' + FID + ' need to be updated');
			if (NeedUpdate || NeedUpload)
				UpdateDatabase()
			else
				dispatchEvent(new ImageEvent(ImageEvent.UPDATE_COMPLETE));
		}
		
		public function UpdateDatabase():void
		{
			FUpdater = new URLLoader();
			FUpdater.addEventListener(Event.COMPLETE, OnUpdate);
			FUpdater.addEventListener(IOErrorEvent.IO_ERROR, OnUploadingIOError);
			FUpdater.addEventListener(SecurityErrorEvent.SECURITY_ERROR, OnUploadingSecurityError);
			var vVars:String = '?id=' + FID;			
			if (!FDelete)
			{
				Cc.logch('Image updating', 'Rotating image on ' + FRotationToSend);
				vVars += '&owner_id=' + FObjectID;
				vVars += '&owner_type=' + FOwnerType;
				vVars += '&order=' + FOrder;			
				if(Description != '' && Description != Constants.DESCRIPTION_CAPTION_DEFAULT)
					vVars += '&description=' + Description;
				if (RotationChanged)
					vVars += '&rotation=' + FRotationToSend;
				vVars += SpecificVars;
				if(!IsLocal)
					FUpdater.load(new URLRequest(Constants.IMAGE_UPDATER + vVars));
				else				
					FUpdater.load(new URLRequest(Constants.IMAGE_CREATOR + vVars));				
			}
			else
			{				
				vVars += '&owner_type=' + FOldType;
				FUpdater.load(new URLRequest(Constants.IMAGE_DELETER + vVars));
			}
		}
		
		protected function get SpecificVars():String 
		{
			var vCurrentType:int = FOwnerType;			
			var vOldType:int = FOldType;
			var vResult:String = '';
			if (vCurrentType != vOldType)
				vResult = '&replace=' + vOldType + ',' + vCurrentType;
			return vResult;
		}
		
		//{ region DBUpdater Listeners
			
		protected function OnUploadingIOError(e:IOErrorEvent):void 
		{
			e.target.removeEventListener(e.type, OnUploadingIOError);
			dispatchEvent(new ImageEvent(ImageEvent.UPDATE_ERROR));
			Cc.errorch('Image updating', 'IO error: ' + e.text);
		}
		
		protected function OnUploadingSecurityError(e:SecurityErrorEvent):void 
		{
			e.target.removeEventListener(e.type, OnUploadingSecurityError);
			dispatchEvent(new ImageEvent(ImageEvent.UPDATE_ERROR));
			Cc.errorch('Image updating', 'Security error: ' + e.text);
		}
		
		protected function OnUpdate(e:Event):void 
		{
			e.target.removeEventListener(e.type, OnUpdate);
			FNeedUpdate = false;			
			FStartDescription = Description;
			if (URLLoader(e.target).data != '')
			{				
				Cc.logch('Image updating', 'Success on ID ' + FID);
				Cc.logch('Image updating', 'Server response: ' + URLLoader(e.target).data);
				if (FIsLocal)
					FID = URLLoader(e.target).data;
				UploadImage();
			}
			else
			{
				dispatchEvent(new ImageEvent(ImageEvent.UPDATE_ERROR));
				Cc.errorch('Image updating', 'Error on ID ' + FID);
			}
		}
		
		//} endregion
		
		public function UploadImage():void
		{	
			if (NeedUpload)
			{
				//do upload;
			}
			//reset upload conditions
			FOldType = FOwnerType;
			FRotationToSend = 0;
			IsLocal = false;	
			dispatchEvent(new ImageEvent(ImageEvent.UPDATE_COMPLETE));
		}
	
		public function Destroy():void
		{
			graphics.clear();
			FDeleter.Destroy();
			if (FBitmap)
			{
				FBitmap.bitmapData.dispose();
				removeChild(FBitmap);
			}
			if (FPreloader)
				FPreloader = null;
			if (FColor)
				FColor = null;
			if (FFilter)
				FFilter = null;
			parent.removeChild(this);
		}
		
		protected function CheckRotationBounds(AValue:int):int
		{
			if (AValue > 90 * 3)
				AValue = 0
			else if (AValue < -90 * 3)
				AValue = 0;					
			return AValue;
		}
		
		//{ Getters & setters
		
		public function get CheckUpdates():Boolean
		{ 
			return FCheckUpdates; 
		} 
		
		public function set CheckUpdates(ACheck:Boolean):void
		{
			FCheckUpdates = ACheck;
		}
		
		public function get ID():int
		{ 
			return FID; 
		}
		
		public function get ObjectID():int 
		{
			return FObjectID;
		}
			
		public function get Order():int
		{
			return FOrder;
		}
		
		public function get MarkedForDelete():Boolean
		{
			return FDelete > 0;
		}
		
		public function get Description():String
		{
			return FDescriptor.Text;
		}		
		
		public function set ID(AID:int):void 
		{
			FID = AID;
		}
		
		public function set ObjectID(AObjectID:int):void
		{			
			FObjectID = AObjectID;
			Cc.logch('Image', 'Image ' + FID + ' owner ' + ' now is ' + FObjectID);
			FRoomsStorage.IsRoom(FObjectID) ? FOwnerType = Constants.OWNER_ROOM : FOwnerType = Constants.OWNER_MAIN;
			if(FOldType == -1)
				FOldType = FOwnerType;
			NotifyUpdate();
		}
		
		public function set Order(AOrder:int):void
		{
			FOrder = AOrder;			
			NotifyUpdate();
		}	
		
		public function set OwnerType(AType:int):void
		{			
			FOwnerType = AType;
			if(FOldType == -1)
				FOldType = FOwnerType;
			NotifyUpdate();
		}
			
		public function set MarkedForDelete(ADelete:Boolean):void
		{
			if (!FIsLocal)
			{			
				FDelete = uint(ADelete);
				FDeleter.Delete = ADelete;			
				NotifyUpdate();
			}
			else
			{
				FViewer.RemoveImage(this);
			}
		}
		
		public function set Description(ADescription:String):void
		{			
			FDescriptor.Text = Utils.ReplaceAllByRegex(ADescription, '&quot;', '"');;
			FStartDescription = FDescriptor.Text;
		}
		
		public function set XMLS(AXMLS:XMLLoader):void
		{
			FRoomsStorage = AXMLS;
		}				
		
		public function get ShowTools():Boolean
		{
			return FTools.visible;
		}
		
		public function set ShowTools(AShow:Boolean):void
		{
			FTools.visible = AShow;
		}
		
		public function get Photo():Bitmap
		{
			return FBitmap;
		}
			
		public function get IsLocal():Boolean		
		{
			return FIsLocal;
		}
		
		public function get IsLoaded():Boolean		
		{
			return FIsLoaded;
		}		
		
		public function set IsLocal(AIsLocal:Boolean):void
		{
			if (FIsLocal != AIsLocal)
			{
				FIsLocal = AIsLocal;
				FDescriptor.Update();
			}
		}
		
		public function set Enabled(AEnabled:Boolean):void
		{
			AEnabled ? FBitmap.filters = [] : FBitmap.filters = [FFilter];
		}
		
		public function get Rotation():int
		{
			return FRotation;
		}
		
		public function get RotationToSend():int
		{
			return FRotationToSend;
		}
		
		public function set Rotation(ARotation:int):void		
		{
			if (FBitmap)
			{				
				var vAngle:int = ARotation - FRotation;
				FRotation = ARotation;								
				FRotationToSend -= vAngle;
				CheckRotationBounds(FRotation);
				CheckRotationBounds(FRotationToSend);
				var vMatrix:Matrix = FBitmap.transform.matrix;			
				var vRect:Rectangle = FBitmap.getBounds(this); 			
				vMatrix.translate(- (vRect.left + (vRect.width / 2)), - (vRect.top + (vRect.height/2))); 			
				vMatrix.rotate((vAngle / 180) * Math.PI);
				vMatrix.translate(vRect.left + (vRect.width / 2), vRect.top + (vRect.height / 2));
				FBitmap.transform.matrix = vMatrix;
			}
		}
		
		public function get NeedUpdate():Boolean 
		{
			return (FNeedUpdate || FIsLocal || (FStartDescription != Description));
		}
		
		public function get RotationChanged():Boolean 
		{
			return FRotationToSend % 360 != 0;
		}
		
		public function get NeedUpload():Boolean 
		{			
			return RotationChanged || FIsLocal;
		}
		
		public function get TipText():String		
		{
			return 'Изображение не найдено';
		}
		
		public function get DeleteText():String		
		{
			var vResult:String = 'Удаление изображения' + '\n';
			if(FIsLocal)
				vResult += "<font color='" + '#666666' + "'>" + 
				'Изображение будет удалено со списка публикации' + "</font>"			
			else
				vResult += "<font color='" + '#666666' + "'>" + 'Изображение будет отмечено на удаление.' + '\n' + 
				'Удаление произойдет после нажатия кнопки "Опубликовать"' + "</font>" + '\n';			
			return vResult;
		}		
		//} endregion
		//End of getters & setters
	}
}